#include "modbus.h"
#include <stdio.h>
#include <modbus.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include "shmem.h"
#include "list.h"
#include <errno.h>
#include "msg_queue_peer.h"
#include "cJSON.h"
#include <stdbool.h>

int msgid;
modbus_t *ctx;

// 消息队列结构体
struct msg_node
{
    long m;
    int key;        // 唯一键值
    char name[128]; // 数据点名称
    int addr;       // 寄存器地址
    bool data;      // 消息队列数据
};

// 内核链表
struct msg_node_list
{
    struct msg_node node;
    struct list_head list;
};
// 定义头节点
struct list_head head;



// 共享内存数据结构体

struct share_stm //stm32数据结构体
{
    BOOL gate;
    BOOL gs;
    BOOL LD1;
    BOOL LD3;
    BOOL FAN;
    BOOL FIRE;
    float temp;
    float humi;
    float Vbat;   
};

struct shm_data  //modbus数据结构体
{
    BOOL door;     //门
    float tem;     // 温度
    float weight;  // 重量
    float in_pre;  // 内部压强
    float air_pre; // 大气压强
    float in_h2;   // 内部氢气浓度
    float out_h2;  // 外部氢气浓度
};
struct shm_data shm_data; // 共享内存结构体

struct share
{
    int id;
    struct shm_data shm_data;
    struct share_stm stm;
};
struct share *share_data;

void *read_pthread(void *p) // 读取modbus slave 寄存器数据
{
    uint16_t data[12] = {};
    uint8_t bitdata[12]={};
    while (1)
    {
        // 读取寄存器
        modbus_read_registers(p, 0, 12, data);
        modbus_read_bits(p, 0, 4, bitdata);
        printf("------------modbus线圈-----------\n\n         %d----%d----%d----%d\n\n",bitdata[0],bitdata[1],bitdata[2],bitdata[3]);
        // 将数据放入共享内存
        share_data->shm_data.tem =  modbus_get_float_dcba(&data[0]);
        share_data->shm_data.weight = modbus_get_float_dcba(&data[2]);
        share_data->shm_data.in_pre= modbus_get_float_dcba(&data[4]);
        share_data->shm_data.air_pre= modbus_get_float_dcba(&data[6]);
        share_data->shm_data.in_h2= modbus_get_float_dcba(&data[8]);
        share_data->shm_data.out_h2= modbus_get_float_dcba(&data[10]);
        printf("------------modbus数据-----------\n\n");
        printf("----------  温度:%.2f ----------\n----------  重量:%.2f ----------\n------  内部压强:%.2f ----------\n------  大气压强:%.2f ----------\n--  内部氢气浓度:%.2f ----------\n--  外部氢气浓度:%.2f ----------\n", share_data->shm_data.tem, share_data->shm_data.weight,share_data->shm_data.in_pre,share_data->shm_data.air_pre,share_data->shm_data.in_h2,share_data->shm_data.out_h2);
        sleep(1);
    }
}

void *write_pthread(void *p) // 读取消息队列控制指令,控制modbus slave 线圈
{
    while (1)
    {
        struct msg_node m1;
        // 读取消息
        msg_queue_recv("msg", &m1, sizeof(m1), 999, 0);
        printf("消息队列:  key:%d  name:%s  addr:%d  data:%d\n", m1.key, m1.name, m1.addr, m1.data);
        // 遍历输出
    struct list_head *pos;
    struct msg_node_list *tmp;
    list_for_each(pos, &head)
    {
        //获取节点的数据域地址
        tmp = list_entry(pos, struct msg_node_list, list);
        printf("%d %d\n",tmp->node.key,tmp->node.addr);
        if(tmp->node.key==m1.key)
        {
            modbus_write_bit(p, tmp->node.addr,m1.data);
            
        }
    }
    }
}



int main(int argc, char const *argv[])
{

    ////////内核链表////////

    // 初始化头节点
    INIT_LIST_HEAD(&head);

   ////////////初始化内核链表////////////////
    //cJSON反序列化   
    // 将node.json文件的数据读取出来
    FILE *fp = fopen("./cJson.json", "r");
    if (fp == NULL)
    {
        perror("fopen err");
        return -1;
    }
    char buf[2048] = "";
    fread(buf, 2048, 1, fp);

    // 反序列化
    //  先得到整个根节点
    cJSON *root = cJSON_Parse(buf);

    // 从根节点中获取名字叫modbus的子节点
    cJSON *modbus = cJSON_GetObjectItem(root, "modbus");
    printf("%s:\n", modbus->string);
    // 从root上获取数组节点data
    cJSON *data = cJSON_GetObjectItem(modbus, "data");
    printf("%s:\n", data->string);
    for (int i = 0; i < cJSON_GetArraySize(data); i++)
    {
        struct msg_node_list  *pnew=(struct msg_node_list *)malloc(sizeof(struct msg_node_list));
        // 从data数组中获取下标为0的子节点
        cJSON *item = cJSON_GetArrayItem(data, i);
        cJSON *key = cJSON_GetObjectItem(item, "key");
        printf("%s:%d\n", key->string, key->valueint);
        cJSON *name = cJSON_GetObjectItem(item, "name");
        printf("%s:%s\n", name->string, name->valuestring);
        cJSON *addr = cJSON_GetObjectItem(item, "addr");
        printf("%s:%d\n", addr->string,addr->valueint);

        pnew->node.key=key->valueint;
        strcpy(pnew->node.name,name->valuestring);
        pnew->node.addr=addr->valueint;
        list_add_tail(&pnew->list,&head);
        printf("key:%d name:%s addr:%d\n",pnew->node.key,pnew->node.name,pnew->node.addr);
    }

    

    ////////共享内存////////
    struct shm_param para;
    shm_init(&para, "shm", 1024);                    // 共享内存初始化
    share_data = (struct share *)shm_getaddr(&para); // 获取共享内存地址
    printf("%p\n",share_data);
    // 创建实例
    ctx = modbus_new_tcp("192.168.31.58",502);
    if (ctx == NULL)
    {
        printf("modbus new tcp\n");
        return -1;
    }
    // 设置从机
    modbus_set_slave(ctx, 1);
    // 建立连接
    modbus_connect(ctx);

    // 创建线程
    pthread_t tid1;
    pthread_t tid2;
    pthread_create(&tid1, NULL, read_pthread, ctx);
    pthread_create(&tid2, NULL, write_pthread, ctx);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    modbus_close(ctx);
    modbus_free(ctx);
    shm_del(&para);
    msgctl(msgid, IPC_RMID, NULL);
    return 0;
}